# -*- coding: utf-8 -*-

"""
@author: bw
@contact: bw@handsdriver.net
"""

import logging

import plumbum.commands as _plmcmd


logger = logging.getLogger('plumbum.vagrant')


class VagrantCommand(_plmcmd.ConcreteCommand):
	__slots__ = ('machine', 'session', 'process')

#	QUOTE_LEVEL = 2  # local
	QUOTE_LEVEL = 1  # remote

	def __init__(self, machine, executable, encoding='auto'):
		self.machine = machine
		self.session = None
		self.process = None

		if encoding == 'auto':
			encoding = machine.custom_encoding

		super().__init__(executable, encoding)

#	def __or__(self, other):
#		return Pipeline(self, other)

	def popen(self, args=(), cwd=None, env=None, **kwargs):
		# @note: BaseCommand.bgrun() --> stdin/stdout/stderr --> close
		#        требуются реальные файловые дескрипторы, используются с `select`-ом, например

		if type(args) is str:
			args = [args]
#		elif isinstance(args, _plmcmd.BaseCommand):
#			args = args.formulate()
		elif isinstance(args, (tuple, list)):
			args = list(args)
		else:
			raise ValueError('Unexpected args', args)

		# self.executable
		# self.formulate(0, args)

		cmdline = ' '.join(self[args].formulate(1))

		assert cwd is None, cwd
		assert env is None, env
		assert self.session is None, cmdline

		popen_kwargs = {}

		if 'stdin'  in kwargs: popen_kwargs['stdin']  = kwargs.pop('stdin')
		if 'stdout' in kwargs: popen_kwargs['stdout'] = kwargs.pop('stdout')
		if 'stderr' in kwargs: popen_kwargs['stderr'] = kwargs.pop('stderr')

		assert not kwargs, kwargs

		def ondone(exc):
			if not exc and not self.session.broken and self.session.alive():
				cwd = self.session.update_cwd()
				env = self.session.update_env()
#				cwd_level.change(cwd)
#				self.machine.cwd = cwd
				self.machine.cwd.change(cwd, cwd_level)
				self.machine.env.clear()
				self.machine.env.update(env)

		self.session = self.machine.getSession()

		with self.session:
			if cmdline and self.session.current_cwd != self.machine.cwd:
				self.session.run('cd ' + _plmcmd.shquote(self.machine.cwd))

			cwd_level = self.machine.cwd.getlevel()

			if cmdline:
				menv = self.machine.env.getdict()
				senv = self.session.current_env

				updates = {key: value for key, value in menv.items() if senv.get(key) != value}
				removes = [key for key in senv.keys() if key not in menv]

#				senv.clear()
#				senv.update(F.project(senv, F.without(senv, *F.concat(removes, updates.keys()))))

				for key in removes:
					del senv[key]

				senv.update(updates)

				# @xxx: `key` нужно проверять, а не квотировать

				if updates:
					self.session.run('; '.join('export {}={}'.format(_plmcmd.shquote(key), _plmcmd.shquote(value))
						for key, value in updates.items()))

				if removes:
					self.session.run('; '.join('unset {}'.format(_plmcmd.shquote(key))
						for key in removes))

			self.process = self.session.popen(cmdline, cbdone=ondone, **popen_kwargs)

		return self.process

#	def nohup(self, cwd='.', stdout='nohup.out', stderr=None, append=True):
#		return self.machine.daemonic_popen(self, cwd, stdout, stderr, append)
